package com.demo.dune.base;

import java.text.SimpleDateFormat;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;

/**
 * WebLogAspect.Pinrt the request and response log.
 * @author Allen
 * @version 1.0 2022-04-05
 */
@Slf4j
@Aspect    
@Component
public class WebLogAspect {

	/**
	 * define effective package path.
	 */
    @Pointcut("execution(public * com.demo.dune.controller..*.*(..))")    
    public void webLog() {}    
    
    /**
     * print request log.
     * @param joinPoint
     * @throws Throwable
     */
    @Before("webLog()")    
    public void doBefore(JoinPoint joinPoint) throws Throwable {       
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();    
        HttpServletRequest request = attributes.getRequest();    
        log.info("========================================== Start ==========================================");     
        log.info("URL            : {}", request.getRequestURL().toString());      
        log.info("HTTP Method    : {}", request.getMethod());     
        log.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), 
        		joinPoint.getSignature().getName()); 
        log.info("IP             : {}", request.getRemoteAddr());    
        // use jackson to format,same with application   
        ObjectMapper mapper = new ObjectMapper();
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));        
        log.info("Request Args   : {}", mapper.writeValueAsString(joinPoint.getArgs()));   
    }    
 
    /**
     * print log after joinPoint.  
     * @throws Throwable
     */
    @After("webLog()")    
    public void doAfter() throws Throwable {    
        log.info("=========================================== End ==========================================="); 
    }    

    /**
     * print response log.
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("webLog()")    
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {    
        long startTime = System.currentTimeMillis();    
        Object result = proceedingJoinPoint.proceed();    
        // use jackson same with application
        ObjectMapper mapper = new ObjectMapper();
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        log.info("Response Args  : {}", mapper.writeValueAsString(result));
        log.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);    
        return result;    
    }   
    
}
